#pragma once
#include "rpc_caller.hpp"
#include "rpc_requestor.hpp"
#include "rpc_topic.hpp"
#include "../common/net.hpp"
#include "../common/dispatcher.hpp"
#include "rpc_register.hpp"
#include <memory>
#include <string>

namespace RPC
{
    namespace Client
    {
        // 服务注册客服端
        class RegisterClient
        {
        public:
            using Ptr = std::shared_ptr<RegisterClient>;

            RegisterClient(const std::string &ip, const int &port)
                : _requestor(std::make_shared<Requestor>()),
                  _provider(std::make_shared<Client::Provider>(_requestor)),
                  _dispatcher(std::make_shared<Dispatcher>())
            {
                // 注册dispatcher回调函数
                auto onServiceResponse =
                    std::bind(&Requestor::onResponse, _requestor.get(),
                              std::placeholders::_1, std::placeholders::_2);
                _dispatcher->registerCallback<BaseMessage>(MType::RES_SERVICE, onServiceResponse);

                // 注册client回调
                auto onMessage = std::bind(&Dispatcher::onMessage, _dispatcher.get(), std::placeholders::_1,
                                           std::placeholders::_2);
                _client = ClientFactory::create(ip, port);
                _client->SetMessageCallback(onMessage);
                _client->connect();
            }

            bool registorMethod(const Address &host, const std::string &method)
            {
                return _provider->registorMethod(_client->conn(), host, method);
            }

        private:
            Requestor::Ptr _requestor;       // 负责服务注册和接收注册结果的回调
            Client::Provider::Ptr _provider; // 进行服务注册的接口
            Dispatcher::Ptr _dispatcher;     // 负责注册requestor回调
            BaseClient::Ptr _client;         // 注册dispatcher回调
        };

        class DiscoverClient
        {
        public:
            using Ptr = std::shared_ptr<DiscoverClient>;
            DiscoverClient(const std::string &ip, const int &port, const Discover::shutConnCallback &cb)
                : _requestor(std::make_shared<Requestor>()),
                  _discover(std::make_shared<Client::Discover>(_requestor, cb)),
                  _dispatcher(std::make_shared<Dispatcher>())
            {
                // 注册dispatcher回调函数
                auto onServiceResponse = std::bind(&Requestor::onResponse, _requestor.get(),
                                                   std::placeholders::_1, std::placeholders::_2);
                _dispatcher->registerCallback<BaseMessage>(MType::RES_SERVICE, onServiceResponse);

                // 注册服务上线下线请求
                auto req_service = std::bind(&Discover::onMessage, _discover.get(), std::placeholders::_1,
                                             std::placeholders::_2);
                _dispatcher->registerCallback<ServiceRequest>(MType::REQ_SERVICE, req_service);

                // 注册client回调
                auto onMessage = std::bind(&Dispatcher::onMessage, _dispatcher.get(), std::placeholders::_1,
                                           std::placeholders::_2);
                _client = ClientFactory::create(ip, port);
                _client->SetMessageCallback(onMessage);
                _client->connect();
            }

            bool serviceDiscover(const std::string &method, Address &host)
            {
                return _discover->serviceDiscover(_client->conn(), method, host);
            }

        private:
            Requestor::Ptr _requestor;       // 负责服务注册和接收注册结果的回调
            Client::Discover::Ptr _discover; // 进行服务注册的接口
            Dispatcher::Ptr _dispatcher;     // 负责注册requestor回调
            BaseClient::Ptr _client;         // 注册dispatcher回调
        };

        class RpcClient
        {
        public:
            using Ptr = std::shared_ptr<RpcClient>;
            // 能否进行服务发现意味着这个是注册中心还是rpc客服端
            RpcClient(bool enable_discover, const std::string &ip, const int &port)
                : _enable_discover(enable_discover),
                  _requestor(std::make_shared<Requestor>()),
                  _dispatcher(std::make_shared<Dispatcher>()),
                  _caller(std::make_shared<RpcCaller>(_requestor))
            {
                // 针对rpc响应进行回调处理 服务中心也需要rpc应答？
                auto handler = std::bind(&Requestor::onResponse, _requestor.get(), std::placeholders::_1,
                                         std::placeholders::_2);
                _dispatcher->registerCallback<BaseMessage>(MType::RES_RPC, handler);
                if (_enable_discover == true)
                {
                    // 启用服务发现，地址是注册中心的地址
                    auto shutcb = std::bind(&RpcClient::del, this, std::placeholders::_1);
                    _discover_client = std::make_shared<DiscoverClient>(ip, port, shutcb);
                }
                else
                {
                    // 未启用服务发现，地址是服务提供者的地址
                    auto msg_cb = std::bind(&Dispatcher::onMessage, _dispatcher.get(), std::placeholders::_1, std::placeholders::_2);
                    _client = ClientFactory::create(ip, port);
                    _client->SetMessageCallback(msg_cb);
                    _client->connect();
                }
            }

            bool send(const std::string &method, const Json::Value &params, RpcCaller::JsonAsyncResponse &async_rsp)
            {
                BaseClient::Ptr client = getClient(method);
                if (client == nullptr)
                    return false;
                return _caller->call(client->conn(), method, params, async_rsp);
            }
            bool send(const std::string &method, const Json::Value &params, Json::Value &result)
            {
                BaseClient::Ptr client = getClient(method);
                if (client == nullptr)
                    return false;
                return _caller->call(client->conn(), method, params, result);
            }
            bool send(const std::string &method, const Json::Value &params, const RpcCaller::JsonCallback &cb)
            {
                BaseClient::Ptr client = getClient(method);
                if (client == nullptr)
                    return false;
                return _caller->call(client->conn(), method, params, cb);
            }

        private:
            void insert(const Address &host, const BaseClient::Ptr &client)
            {
                std::unique_lock<std::mutex> lock(_mutex);
                _clients.insert({host, client});
            }

            void del(const Address &host)
            {
                std::unique_lock<std::mutex> lock(_mutex);
                fflush(stdout);
                _clients.erase(host);
            }

            BaseClient::Ptr getClient(const Address &host)
            {
                std::unique_lock<std::mutex> lock(_mutex);
                auto it = _clients.find(host);
                if (it == _clients.end())
                {
                    return BaseClient::Ptr();
                }
                else
                {
                    return it->second;
                }
            }

            BaseClient::Ptr getClient(const std::string &method)
            {
                BaseClient::Ptr client;
                if (_enable_discover == true)
                {
                    Address host;
                    bool ret = _discover_client->serviceDiscover(method, host);
                    if (ret == false)
                    {
                        ERROR_LOG("服务发现失败！");
                        return BaseClient::Ptr();
                    }
                    client = getClient(host);
                    if (client.get() == nullptr)
                    {
                        client = newClient(host);
                    }
                }
                else
                {
                    client = _client;
                }
                return client;
            }

            BaseClient::Ptr newClient(const Address &host)
            {
                auto msg_cb = std::bind(&Dispatcher::onMessage, _dispatcher.get(), std::placeholders::_1, std::placeholders::_2);
                BaseClient::Ptr client = ClientFactory::create(host.first, host.second);
                client->SetMessageCallback(msg_cb);
                client->connect();
                insert(host, client);
                return client;
            }
            struct AddressHash
            {
                size_t operator()(const Address &host) const
                {
                    std::string key = host.first + std::to_string(host.second);
                    return std::hash<std::string>{}(key);
                }
            };

            bool _enable_discover;
            DiscoverClient::Ptr _discover_client; // 注册了服务发现，连接注册中心
            Requestor::Ptr _requestor;
            RpcCaller::Ptr _caller;
            Dispatcher::Ptr _dispatcher;
            BaseClient::Ptr _client; // 用于未启用服务发现，充当普通客服端功能
            // 用于启用了服务发现的客服端连接池
            std::mutex _mutex;
            std::unordered_map<Address, BaseClient::Ptr, AddressHash> _clients;
        };

        class TopicClient
        {
        public:
            using Ptr = std::shared_ptr<TopicClient>;
            TopicClient(const std::string &ip, const int &port)
                : _requestor(std::make_shared<Requestor>()),
                  _dispatcher(std::make_shared<Dispatcher>()),
                  _topicmanager(std::make_shared<TopicManager>(_requestor))
            {
                // 注册dispatcher回调函数
                auto onTopicResponse = std::bind(&Requestor::onResponse, _requestor.get(),
                                                 std::placeholders::_1, std::placeholders::_2);
                _dispatcher->registerCallback<BaseMessage>(MType::RES_TOPIC, onTopicResponse);

                auto topic_onpublic_cb = std::bind(&TopicManager::onPublish, _topicmanager.get(), std::placeholders::_1,
                                                   std::placeholders::_2);

                _dispatcher->registerCallback<TopicRequest>(MType::REQ_TOPIC, topic_onpublic_cb);
                // 注册client回调
                auto onMessage = std::bind(&Dispatcher::onMessage, _dispatcher.get(), std::placeholders::_1,
                                           std::placeholders::_2);
                _client = ClientFactory::create(ip, port);
                _client->SetMessageCallback(onMessage);
                _client->connect();
            }

            bool topicSubscribe(const std::string &topic, const TopicManager::MsgCallBack &cb)
            {
                return _topicmanager->topicSubscribe(_client->conn(), topic, cb);
            }
            bool topicCancle(const std::string &topic)
            {
                return _topicmanager->topicCancle(_client->conn(), topic);
            }
            bool topicCreate(const std::string &topic)
            {
                return _topicmanager->topicCreate(_client->conn(), topic);
            }
            bool topicRemove(const std::string &topic)
            {
                return _topicmanager->topicRemove(_client->conn(), topic);
            }
            bool topicPublish(const std::string &topic, const std::string &msg)
            {
                return _topicmanager->topicPublish(_client->conn(), topic, msg);
            }

            void shutdown()
            {
                _client->shutdown();
            }

        private:
            Requestor::Ptr _requestor;
            Dispatcher::Ptr _dispatcher;
            TopicManager::Ptr _topicmanager; // 管理主题信息
            BaseClient::Ptr _client;
        };
    }
}